package net.gdface.sdk;

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;

import net.gdface.annotation.DeriveMethod;
import net.gdface.annotation.GenericParam;
import net.gdface.image.ImageErrorException;

/**
 * 
 * 人脸识别SDK核心接口<br>
 * 此接口中所有byte[]类型的图像参数都指未解码的图像格式(如jpg,bmp,png...),<br>
 * 目前支持的图像格式类型依赖于{@link javax.imageio.ImageIO}的支持能力
 * @author guyadong
 */
public interface FaceApi {

	/**
	 * 对人脸图像提取特征码，返回比较相似度结果<br>
	 * imgData1和imgData2相等或imgData2为{@code null}时,即比较同一张图像中的两张人脸的相似度
	 * 调用该方法时假设图像({@code imgData1}和{@code imgData2})能正常解码,<br>
	 * 所以当对图像解码出现异常时，将{@link ImageErrorException}异常对象封装到{@link RuntimeException}抛出<br>
	 * 任何参数为{@code null}则抛出{@link IllegalArgumentException}
	 * @param imgData1
	 *            　图像1数据字节数组
	 * @param facePos1
	 *            检测到的人脸/眼睛位置
	 * @param imgData2
	 *            　图像1数据字节数组
	 * @param facePos2
	 *            检测到的人脸/眼睛位置
	 * @return 两张人脸之间的相似度(0.0~1)
	 * @throws NotFaceDetectedException
	 * @throws ImageErrorException
	 * @see #getCodeInfo(byte[], int, CodeInfo[])
	 * @see #compareCode(byte[], byte[])
	 */
	@DeriveMethod(localResolvedTypes={InputStream.class,URL.class,File.class,ByteBuffer.class})
	public abstract double compare2Face(
			@GenericParam(name="T1")byte[] imgData1, 
			CodeInfo facePos1, 
			@GenericParam(name="T2")byte[] imgData2, 
			CodeInfo facePos2)
			throws NotFaceDetectedException, ImageErrorException;

	/**
	 * 对两个图像指定范围({@link FRect})进行人脸检测,找到并提取唯一的人脸特征码,然后比较相似度,返回相似度结果<br>
	 * imgData1和imgData2相等或imgData2为{@code null}时,
	 * 即比较同一张图像中的两张人脸的相似度,这种情况下detectRect1和detectRect2都不能为{@code null}<br>
	 * imgData1和imgData2不相等且都不为{@code null}时,detectRect1和detectRect2被忽略
	 * 
	 * @param imgData1
	 *            图像1数据字节数组,为{@code null}则抛出{@link IllegalArgumentException}
	 * @param detectRect1
	 *            图片检测范围，为null时全图检测
	 * @param imgData2
	 *            图像2数据字节数组
	 * @param detectRect2
	 *            图片检测范围，为null时全图检测
	 * @return 两张人脸之间的相似度(0.0~1)
	 * @throws ImageErrorException
	 * @throws NotFaceDetectedException
	 * @see #detectAndGetCodeInfo(byte[], int)
	 * @see #compareCode(byte[], byte[])
	 */
	@DeriveMethod(localResolvedTypes={InputStream.class,URL.class,File.class,ByteBuffer.class})
	public abstract double detectAndCompare2Face(
			@GenericParam(name="T1")byte[] imgData1, 
			FRect detectRect1, 
			@GenericParam(name="T2")byte[] imgData2, 
			FRect detectRect2)
			throws ImageErrorException, NotFaceDetectedException;

	/**
	 * 特征码比对<br>
	 * 参数为{@code null}或长度不一致则抛出{@link IllegalArgumentException}异常
	 * @param code1 待比对的特征码
	 * @param code2 待比对的特征码
	 * @return 两个特征码之间的相似度（0.0~1）
	 */
	public abstract double compareCode(@GenericParam(name="T1")byte[] code1, @GenericParam(name="T2")byte[] code2);

	/**
	 * 特征码比对1:N<br>
	 * @param code1
	 * @param codes 包含人脸特征的{@link CodeInfo }数组
	 * @return 返回对应的特征码相似度数组
	 */
	public abstract double[] compareCodes(byte[] code1, CodeInfo[] codes);
	/**
	 * 特征码比对1:N<br>
	 * 对{@code imgData}图像数据检测人脸并提取特征，然后与{@code code}特征进行比对
	 * @param code 人脸特征数据
	 * @param imgData 待比对的图像(可能有多张人脸)
	 * @param faceNum  参见 {@link #getCodeInfo(byte[], int, CodeInfo[])}
	 * @return 包含比对相似度结果的映射，{CodeInfo - 相似度}值对
	 * @throws NotFaceDetectedException
	 * @throws ImageErrorException
	 * @see #compareCodes(byte[], CodeInfo[])
	 * @see #detectAndGetCodeInfo(byte[], int)
	 */
	@DeriveMethod(localResolvedTypes={InputStream.class,URL.class,File.class,ByteBuffer.class})
	Map<CodeInfo, Double> compareFaces(
			@GenericParam(name="T1")byte[] code, 
			@GenericParam(name="T2")byte[] imgData, 
			int faceNum)
	throws NotFaceDetectedException, ImageErrorException;

	/**
	 * 特征码比对1:N<br>
	 * @param code1
	 * @param codes 一组人脸特征
	 * @return 返回对应的特征码相似度列表
	 */
	public abstract List<Double> compareFeatures(byte[] code1, List<byte[]> codes);

	/**
	 * 先对图像数据{@code imgData}进行人脸检测，然后提取人脸特征码<br>
	 * 
	 * @param imgData
	 *            图像数据字节数组,为{@code null}则抛出{@link IllegalArgumentException}
	 * @param faceNum
	 *            参见 {@link #getCodeInfo(byte[], int, CodeInfo[])}
	 * @return 返回所有成功提取特征码的{@link CodeInfo}对象<br>
	 *         与{@link #getCodeInfo(byte[], int, CodeInfo[])}的返回结果有差别，返回结果中不包含检测到人脸但提取特征码失败的对象
	 * @throws ImageErrorException
	 * @throws NotFaceDetectedException 没有检测人脸或提取到特征码的人脸数目不是要求的人脸数目(faceNum>0)
	 */
	@DeriveMethod(localResolvedTypes={InputStream.class,URL.class,File.class,ByteBuffer.class})
	public abstract CodeInfo[] detectAndGetCodeInfo(byte[] imgData, int faceNum)
			throws ImageErrorException, NotFaceDetectedException;

	/**
	 * 对图像({@code imgData})进行人脸检测，返回人脸位置数据对象{@link FRect}数组<br>
	 * 
	 * @param imgData
	 *            图像数据字节数组,为{@code null}则抛出{@link IllegalArgumentException}
	 * @return 没有检测到人脸则返回空数组
	 * @throws ImageErrorException
	 */
	@DeriveMethod(localResolvedTypes={InputStream.class,URL.class,File.class,ByteBuffer.class})
	public abstract CodeInfo[] detectFace(byte[] imgData) throws ImageErrorException;

	/**
	 * 检测最中心的人脸
	 * @param imgData
	 * @return
	 * @throws NotFaceDetected
	 * @throws ImageError
	 */
	public abstract CodeInfo detectCenterFace(byte[] imgData) throws NotFaceDetectedException, ImageErrorException;

	/**
	 * 根据{@code facePos}提供的人脸信息位置, 在{@code imgData}图像中提取特征码<br>
	 * 与 {@link #detectAndGetCodeInfo(byte[], int)}不同, 本方法不对图像数据{@code imgData}进行人脸检测,<br>
	 * 假设{@code facePos}是 {@link #detectFace(byte[])}或 {@link #detectFaceAgain(byte[], FRect[])} 的返回结果<br>
	 * @param imgData
	 *           图像数据字节数组,为{@code null}则抛出 {@link IllegalArgumentException} 
	 * @param faceNum
	 *            要求返回的人脸特征码数目<br>
	 *            大于0时，如果实际提取到的人脸特征码数目不等于{@code faceNum},则抛出{@link NotFaceDetectedException}<br>
	 *            小于等于0时，返回所有提取到到人脸特征码 
	 * @param facePos
	 *            检测到的人脸位置对象列表<br>
	 *            为{@code null}或数组长度为0时抛出{@link IllegalArgumentException}<br>
	 *            如果元素为{@code null},则跳过<br>
	 * @return 返回facePos<br>	         
	 *         如果没有提取到特征码,则对应元素{@link CodeInfo#getCode()}返回{@code null}
	 * @throws NotFaceDetectedException 提取特征码的人脸数目为0或没有提取到指定数目(faceNum>0)的特征码
	 */
	@DeriveMethod(localResolvedTypes={InputStream.class,URL.class,File.class,ByteBuffer.class})
	public abstract CodeInfo[] getCodeInfo(byte[] imgData, int faceNum, CodeInfo[] facePos) throws NotFaceDetectedException;

	/**
	 * 根据{@code facePos}提供的人脸信息位置, 在{@code imgData}图像中提取特征码<br>
	 * @param imgData
	 * @param facePos
	 * @return 返回包含人脸特征的{@link CodeInfo}对象，提取特征失败则返回{@code null}
	 */
	@DeriveMethod(methodSuffix="Single",localResolvedTypes={InputStream.class,URL.class,File.class,ByteBuffer.class})
	public CodeInfo getCodeInfo(byte[] imgData, CodeInfo facePos);

	/**
	 * 多张人脸提取特征
	 * @param faces
	 * @return
	 * @throws NotFaceDetectedException 
	 */
	public abstract byte[] getFeature(Map<ByteBuffer,CodeInfo>faces) throws NotFaceDetectedException;
 	/**
	 * 判断图像是否能提取到人脸特征码
	 * 
	 * @param imgData
	 *            图像数据字节数组,为{@code null}则抛出{@link IllegalArgumentException}
	 * @return 为{@code true}则能检测到人脸并能提取特征码
	 * @throws ImageErrorException
	 * @see #detectAndGetCodeInfo(byte[], int)
	 */
	@DeriveMethod(localResolvedTypes={InputStream.class,URL.class,File.class,ByteBuffer.class})
	public abstract boolean hasFace(byte[] imgData) throws ImageErrorException;

	/**
	 * 是否支持多张人脸合成特征
	 * @return
	 */
	public abstract boolean multiFaceFeature();
	/**
	 * 返回当前接口实现方式<br> 
	 * false WebService类型<br>
	 * true 本地实现
	 * @return　boolean
	 */
	public abstract boolean isLocal();
}